#include "serialPort.h"
#include <string.h>
#include <sys/ioctl.h>
using namespace std;


serialPort::serialPort()
{
	fd=-1;
}

bool serialPort::OpenPort(const char * dev)
{

	char* _dev=new char[32];
	strcpy(_dev,dev);
	fd = open(_dev, O_RDWR);         //| O_NOCTTY | O_NDELAY   
	if (-1 == fd)   
	{           
		perror("Can't Open Serial Port");
		return -1;      
	}   

	int DTR_flag;
	DTR_flag = TIOCM_DTR;
	ioctl(fd,TIOCMBIS,&DTR_flag);//Set RTS pin
	return 0;
}

int serialPort::setup(int speed,int flow_ctrl,int databits,int stopbits,int parity)  
{  
	int   i, speed_setted = 0;  
	int   status; 
	struct termios options;	
	/*tcgetattr(fd,&options)得到与fd指向对象的相关参数，并将它们保存于options,该函数还可以测试配置是否正确，该串口是否可用等。若调用成功，函数返回值为0，若调用失败，函数返回值为1. 
	 *     */  
	if( tcgetattr( fd,&options)  !=  0)  
	{  
		perror("SetupSerial 1");      
		return -1;
	}  

	//设置串口输入波特率和输出波特率  
	for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)  
	{  
		if  (speed == name_arr[i])  
		{               
			cfsetispeed(&options, speed_arr[i]);   
			cfsetospeed(&options, speed_arr[i]);    
			speed_setted = 1;
		}  
	}       

	if(!speed_setted)
	{
		fprintf(stderr, "invalid baudrate, check and set a new value\n");
		return -1;
	}

	//修改控制模式，保证程序不会占用串口  
	options.c_cflag |= CLOCAL;  

	//修改控制模式，使得能够从串口中读取输入数据  
	options.c_cflag |= CREAD;  

	//设置数据流控制  
	switch(flow_ctrl)  
	{  

		case 0 ://不使用流控制  
			options.c_cflag &= ~CRTSCTS;  
			break;     

		case 1 ://使用硬件流控制  
			options.c_cflag |= CRTSCTS;  
			break;  
		case 2 ://使用软件流控制  
			options.c_cflag |= IXON | IXOFF | IXANY;  
			break;  
	}  

	//设置数据位  
	//屏蔽其他标志位  
	options.c_cflag &= ~CSIZE;  
	switch (databits)  
	{    
		case 5    :  
			options.c_cflag |= CS5;  
			break;  
		case 6    :  
			options.c_cflag |= CS6;  
			break;  
		case 7    :      
			options.c_cflag |= CS7;  
			break;  
		case 8:      
			options.c_cflag |= CS8;  
			break;    
		default:     
			fprintf(stderr,"Unsupported data size\n");  
			return -1;
	}  

	//设置校验位  
	switch (parity)  
	{    
		case 'n':  
		case 'N': //无奇偶校验位。  
			options.c_cflag &= ~PARENB;   
			options.c_iflag &= ~INPCK;      
			break;   
		case 'o':    
		case 'O'://设置为奇校验      
			options.c_cflag |= (PARODD | PARENB);   
			options.c_iflag |= INPCK;               
			break;   
		case 'e':   
		case 'E'://设置为偶校验    
			options.c_cflag |= PARENB;         
			options.c_cflag &= ~PARODD;         
			options.c_iflag |= INPCK;        
			break;  
		case 's':  
		case 'S': //设置为空格   
			options.c_cflag &= ~PARENB;  
			options.c_cflag &= ~CSTOPB;  
			break;   
		default:    
			fprintf(stderr,"Unsupported parity\n");      
			return -1;
	}   
	//
	// 设置停止位   
	switch (stopbits)  
	{    
		case 1:     
			options.c_cflag &= ~CSTOPB; break;   
		case 2:     
			options.c_cflag |= CSTOPB; break;  
		default:     
			fprintf(stderr,"Unsupported stop bits\n");   
			return -1;
	}  

	//修改输出模式，原始数据输出  
	options.c_oflag &= ~OPOST;  

	options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  
	//options.c_lflag &= ~(ISIG | ICANON);  

	//设置等待时间和最小接收字符  
	options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */    
	options.c_cc[VMIN] = 1; /* 读取字符的最少个数为1 */  

	//如果发生数据溢出，接收数据，但是不再读取 刷新收到的数据但是不读  
	tcflush(fd,TCIFLUSH);  

	//激活配置 (将修改后的termios数据设置到串口中）  
	if (tcsetattr(fd,TCSANOW,&options) != 0)    
	{  
		perror("com set error!\n");    
		return -1;
	}  

	return 0;
}  

int serialPort::readBuffer(char * buffer,int size)
{
	return read(fd, buffer, size);
}

int serialPort::writeBuffer(char * buffer,int size)
{
	return write(fd, buffer ,size);
}

uint8_t serialPort::getchar()
{
	uint8_t t;
	read(fd, &t, 1);
	return t;
}

void serialPort::ClosePort()
{
	close(fd);
}
